package org.adw.library.widgets.discreteseekbar.internal.drawable;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.ComponentState;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar;
import org.adw.library.widgets.discreteseekbar.internal.ColorStateList;

public class AlmostRippleDrawable {
    private static final long FRAME_DURATION = 1000 / 60;
    private static final int ANIMATION_DURATION = 250;
    private static final float INACTIVE_SCALE = 0f;
    private static final float ACTIVE_SCALE = 1f;
    private float mCurrentScale = INACTIVE_SCALE;
    private float mAlpha = 1f;
    private int mPressedColor;
    private int mFocusedColor;
    private int mDisabledColor;
    private int mRippleColor;
    private AnimatorValue animatorValue = new AnimatorValue();
    private DiscreteSeekBar discreteSeekBar;
    private Paint paint = new Paint();

    private boolean needNormal;

    public AlmostRippleDrawable(ColorStateList tintStateList, DiscreteSeekBar discreteSeekBar) {
        this.discreteSeekBar = discreteSeekBar;
        int defaultColor = tintStateList.getDefaultColor();
        mFocusedColor =
                tintStateList.getColorForState(new int[] {ComponentState.COMPONENT_STATE_FOCUSED}, defaultColor);
        mPressedColor =
                tintStateList.getColorForState(new int[] {ComponentState.COMPONENT_STATE_PRESSED}, defaultColor);
        mDisabledColor =
                tintStateList.getColorForState(new int[] {ComponentState.COMPONENT_STATE_DISABLED}, defaultColor);
        mRippleColor = defaultColor;

        mFocusedColor = getModulatedAlphaColor(100, mFocusedColor);
        mPressedColor = getModulatedAlphaColor(100, mPressedColor);
        mDisabledColor = getModulatedAlphaColor(100, mDisabledColor);
        mRippleColor = getModulatedAlphaColor(100, mRippleColor);
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL_STYLE);
    }

    private static int getModulatedAlphaColor(int alphaValue, int originalColor) {
        int alpha = Color.alpha(originalColor);
        int scale = alphaValue + (alphaValue >> 7);
        alpha = alpha * scale >> 8;
        RgbColor rgbColor = RgbColor.fromArgbInt(originalColor);
        return Color.argb(alpha, rgbColor.getRed(), rgbColor.getGreen(), rgbColor.getBlue());
    }

    public void doDraw(Canvas canvas, float x, float y, float radius) {
        if (!discreteSeekBar.isEnabled()) {
            paint.setColor(new Color(mDisabledColor));
            canvas.drawCircle(x, y, radius, paint);
        } else if (mAlpha != 0) {
            radius = radius * mCurrentScale;
            paint.setColor(new Color(getAnimateColor(mRippleColor, mPressedColor, mCurrentScale).asArgbInt()));
            float alpha = paint.getAlpha();
            paint.setAlpha(alpha * mAlpha);
            canvas.drawCircle(x, y, radius, paint);
        } else if (discreteSeekBar.isFocused()) {
            paint.setColor(new Color(mFocusedColor));
            canvas.drawCircle(x, y, radius, paint);
        }
    }

    public void animateToPressed() {
        if (animatorValue != null && animatorValue.isRunning()) {
            animatorValue.stop();
        }
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setDuration((long) (ANIMATION_DURATION - mAlpha * ANIMATION_DURATION));
        float start = mAlpha;
        float end = 1;
        animatorValue.setValueUpdateListener(
                (animatorValue, v) -> {
                    mCurrentScale = start + (end - start) * v;
                    mAlpha = start + (end - start) * v;
                    discreteSeekBar.getContext().getUITaskDispatcher().asyncDispatch(
                                    () -> discreteSeekBar.invalidate());
                });
        animatorValue.setStateChangedListener(
                new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {}

                    @Override
                    public void onStop(Animator animator) {}

                    @Override
                    public void onCancel(Animator animator) {}

                    @Override
                    public void onEnd(Animator animator) {
                        if (needNormal) {
                            needNormal = false;
                            animatorValue.setDuration((long) (mAlpha * ANIMATION_DURATION));
                            float start = mAlpha;
                            float end = 0;
                            animatorValue.setValueUpdateListener(
                                    (animatorValue, v) -> {
                                        mAlpha = start + (end - start) * v;
                                        discreteSeekBar.getContext().getUITaskDispatcher().asyncDispatch(
                                                        () -> discreteSeekBar.invalidate());
                                    });
                            animatorValue.start();
                        }
                    }
                    @Override
                    public void onPause(Animator animator) {}

                    @Override
                    public void onResume(Animator animator) {}
                });
        animatorValue.start();
    }

    public void animateToNormal() {
        if (animatorValue != null && animatorValue.isRunning()) {
            needNormal = true;
            return;
        }
        animatorValue.setDuration((long) (mAlpha * ANIMATION_DURATION));
        float start = mAlpha;
        float end = 0;
        animatorValue.setValueUpdateListener(
                (animatorValue, v) -> {
                    mAlpha = start + (end - start) * v;
                    discreteSeekBar
                            .getContext()
                            .getUITaskDispatcher()
                            .asyncDispatch(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            discreteSeekBar.invalidate();
                                        }
                                    });
                });
        animatorValue.start();
    }

    public void setColor(int color) {
        mFocusedColor = color;
        mPressedColor = color;
        mDisabledColor = color;
        mRippleColor = color;

        mFocusedColor = getModulatedAlphaColor(130, mFocusedColor);
        mPressedColor = getModulatedAlphaColor(130, mPressedColor);
        mDisabledColor = getModulatedAlphaColor(130, mDisabledColor);
        discreteSeekBar.invalidate();
    }

    public void setColorStateList(ColorStateList colorStateList) {
        int defaultColor = colorStateList.getDefaultColor();
        mFocusedColor =
                colorStateList.getColorForState(new int[] {ComponentState.COMPONENT_STATE_FOCUSED}, defaultColor);
        mPressedColor =
                colorStateList.getColorForState(new int[] {ComponentState.COMPONENT_STATE_PRESSED}, defaultColor);
        mDisabledColor =
                colorStateList.getColorForState(new int[] {ComponentState.COMPONENT_STATE_DISABLED}, defaultColor);
        mRippleColor = defaultColor;

        mFocusedColor = getModulatedAlphaColor(130, mFocusedColor);
        mPressedColor = getModulatedAlphaColor(130, mPressedColor);
        mDisabledColor = getModulatedAlphaColor(130, mDisabledColor);
        discreteSeekBar.invalidate();
    }

    public RgbColor getAnimateColor(int from, int to, float v) {
        RgbColor a = RgbColor.fromArgbInt(from);
        RgbColor b = RgbColor.fromArgbInt(to);
        int red = (int) (a.getRed() + (b.getRed() - a.getRed()) * v);
        int blue = (int) (a.getBlue() + (b.getBlue() - a.getBlue()) * v);
        int green = (int) (a.getGreen() + (b.getGreen() - a.getGreen()) * v);
        int alpha = (int) (a.getAlpha() + (b.getAlpha() - a.getAlpha()) * v);
        RgbColor mCurrentColorRgb = new RgbColor(red, green, blue, alpha);
        return mCurrentColorRgb;
    }
}
